package cn.jilian.meta.web;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import com.fasterxml.jackson.databind.ObjectMapper;

import cn.jilian.common.domain.R;
import cn.jilian.common.dto.FilterPageSortQuery;
import cn.jilian.common.dto.PageResult;
import cn.jilian.common.util.MapUtil;
import cn.jilian.entity.MField;
import cn.jilian.entity.Meta;
import cn.jilian.meta.service.DataService;
import cn.jilian.meta.service.MetaService;
import cn.jilian.meta.service.domain.SimpleList;
import io.swagger.annotations.ApiOperation;

@RestController
@RequestMapping("/meta")
public class MetaController {
	
	@Resource(name="upperCaseJdbcTemplate")
	private JdbcTemplate jdbcTemplate;
	
	@Autowired
	private MetaService metaService;
	
	@Autowired
	private DataService dataService;
	
	@Autowired
	private Environment env;
	
	@Autowired
	private ObjectMapper objectMapper;
	
	
	@GetMapping("/{id}")
	public List<Meta> getMetaTree(@PathVariable("id")Long id){
		return metaService.querySubMetas(id);
	}
	
	@GetMapping("/definition")
	public R getMetaById(@RequestParam("id")Long id){
		try {
			Meta meta= metaService.getMetaById(id);
			return R.ok(meta);
		}catch(Exception e) {
			return R.fail("查询失败:"+e.getMessage());
		}
	}
	@PutMapping("")
	public R addMeta(Meta meta) {
		try {
			metaService.addMeta(meta);
			return R.ok(meta);
		}catch(Exception e) {
			return R.fail("新增失败:"+e.getMessage());
		}
	}
	
	@PostMapping("")
	public R updateMeta(Meta meta) {
		try {
			metaService.updateMeta(meta);
			return R.ok;
		}catch(Exception e) {
			e.printStackTrace();
			return R.fail("更新失败"+e.getMessage());
		}
	}
	
	@DeleteMapping("/{id}")
	public R deleteMeta(@PathVariable("id")Long id) {
		try {
			metaService.deleteMeta(id);
			return R.ok("");
		}catch(Exception e) {
			return R.fail("新增失败");
		}
	}
	
	@SuppressWarnings("unchecked")
	private void putSessionEnvDefaultValue(Map<String,Object> data,HttpSession session,Meta meta) {
		Map<String,Object> defaultFilterMap=(Map<String, Object>) meta.getAttr("filter");
		for(Map.Entry<String, Object> e:defaultFilterMap.entrySet()) {
			String k=e.getKey();
			Object v=e.getValue();
			if(String.class.isAssignableFrom(v.getClass())) {
				String refValue=(String)v;
				if(StringUtils.startsWith(refValue, "${session.")) {
					String key=StringUtils.substringBetween(refValue, "${session.", "}");
					String[] keys=StringUtils.split(key,".");
					if(keys.length==1) {
						Object realValue=session.getAttribute(key);
						data.put(k, realValue);
					}else {
						Map o1=objectMapper.convertValue(session.getAttribute(keys[0]), Map.class);
						for(int i=1;i<keys.length;i++) {
							if(i<keys.length-1) {
								o1=objectMapper.convertValue(o1.get(keys[i]), Map.class);
							}else {
								Object realValue=o1.get(keys[i]);
								data.put(k, realValue);
							}
						}
					}
					
				}else if(StringUtils.startsWith(refValue, "${env.")) {
					String key=StringUtils.substringBetween(refValue, "${env.", "}");
					data.put(k, env.getProperty(key));
				}else {
					data.put(k, v);
				}
			}
			else {
				data.put(k, v);
			}
		}
	}
	
	@GetMapping("/singleRecord/{metaId}")
	public R getSingleRecord(@PathVariable("metaId")Long metaId,@RequestParam Map<String,Object> filterMap,HttpSession session) {
		try {
		Meta meta=metaService.getMetaById(metaId);
		if(filterMap==null) {
			filterMap=new HashMap<>();
		}
		filterMap.remove("_dc");
		if(meta.getMetaId().equals(Meta.VIEW_META)) {
			Long refMetaId=meta.getAttr(Meta.REFMODELID, meta.getFid());
			putSessionEnvDefaultValue(filterMap,session,meta);
			Meta refMeta=metaService.getMetaById(refMetaId);
			Map<String,Object> record=metaService.query(refMeta, filterMap);
			return R.ok(record);
		}else if(meta.getMetaId().equals(Meta.MODULE_META)
		||meta.getMetaId().equals(Meta.TRAIT_MODEL_META)		
				) {
			if(filterMap.containsKey("id")) {
				Long id=objectMapper.convertValue(filterMap.get("id"), Long.class);
				Map<String,Object> record=	metaService.getRecord(meta, id);
				return R.ok(record);
			}
		}
		Map<String,Object> record=metaService.query(meta, filterMap);
		return R.ok(record);
		}catch(Exception e) {
			e.printStackTrace();
			return R.fail("查询失败");
		}
	}
	
	@GetMapping("/getChildren/{metaId}")
	public List<Map<String,Object>> getChildren(@PathVariable("metaId")Long metaId,@RequestParam("id")Long id){
		try {
			return metaService.getChildren(metaId, id);
		}catch(Exception e) {
			return null;
		}
	}
	
	@GetMapping("/getAllChildren/{metaId}/{id}")
	public List<Map<String,Object>> getAllChildren(@PathVariable("metaId")Long metaId,@PathVariable("id")Long id){
		try {
			return metaService.getAllChildren(metaId, id);
		}catch(Exception e) {
			return null;
		}
	}
	

	
	@GetMapping("/record/{metaId}")
	public PageResult<Map<String,Object>> restfulPageQuery(@PathVariable("metaId")Long metaId,
			@RequestParam Map<String,Object> requestParams,HttpSession session){
		Map<String,Object> data=MapUtil.expand(requestParams);
		
		FilterPageSortQuery query=objectMapper.convertValue(data, FilterPageSortQuery.class);
		Meta meta=metaService.getMetaById(metaId);
		if(meta.getMetaId().equals(Meta.VIEW_META)) {
			Long refMetaId=meta.getAttr(Meta.REFMODELID, meta.getFid());
			Map<String,Object> filterMap=query.getFilter();
			if(filterMap==null) {
				filterMap=new HashMap<>();
				query.setFilter(filterMap);
			}
			putSessionEnvDefaultValue(filterMap,session,meta);
			return metaService.pageQuery(refMetaId, query);
			
		}
		return metaService.pageQuery(meta, query);
	}
	
	@PutMapping("/record/{metaId}")
	public R addRecordRest(@PathVariable Long metaId,@RequestParam Map<String,Object> record,HttpSession session) {
		try {
			int r=0;
			Meta meta=metaService.getMetaById(metaId);
			if(meta.getMetaId().equals(Meta.VIEW_META)) {
				Long refMetaId=meta.getAttr(Meta.REFMODELID, meta.getFid());
				putSessionEnvDefaultValue(record,session,meta);
				r=metaService.addRecord(refMetaId,record);
			}else {
				r=metaService.addRecord(meta,record);
			}
			if(r==0) {
				return R.fail("更新失败");
			}
			return R.ok;
		}catch(Exception e) {
				return R.fail(e.getMessage());
		}
	}
	
	@PostMapping("/record/{metaId}")
	public R updateRecordRest(@PathVariable Long metaId,@RequestParam Map<String,Object> record,HttpSession session) {
		try {
			int r=0;
			Meta meta=metaService.getMetaById(metaId);
			Long rmetaId=meta.getMetaId();
			if(rmetaId.equals(Meta.VIEW_META)) {
				Long refMetaId=meta.getAttr(Meta.REFMODELID, meta.getFid());
				putSessionEnvDefaultValue(record,session,meta);
				r=metaService.updateRecord(refMetaId,record);
			}else if(rmetaId.equals(Meta.TRAIT_MODEL_META)){
				long id=objectMapper.convertValue(record.get("id"), Long.class);
				r=metaService.saveTraits(id, record, metaId);
			}else {
				r=metaService.updateRecord(meta,record);
			}
			if(r==0) {
				return R.fail("更新失败");
			}
			return R.ok;
		}catch(Exception e) {
			e.printStackTrace();
			return R.fail("更新失败");
		}
	}
	
	@DeleteMapping("/record/{metaId}/{id}")
	public R deleteRecordRestful(@PathVariable("metaId") Long metaId,@PathVariable("id")Long id) {
		try {
			metaService.deleteRecord(id,metaId);
			return R.ok;
		}catch(Exception e) {
			e.printStackTrace();
			return R.fail;
		}
	}
	
	@RequestMapping(value="/record/move/{metaId}",method= {RequestMethod.GET,RequestMethod.POST})
	public R moveRecord(@PathVariable("metaId")Long metaId,@RequestParam("fid")Long fid,@RequestParam("seq")Long seq,@RequestParam("id")Long id) {
		try {
			metaService.moveRecord(metaId, id, fid, seq);
			return R.ok;
		}catch(Exception e) {
			e.printStackTrace();
			return R.fail;
		}
	}
	
	@RequestMapping(value="/record/offset/{metaId}",method= {RequestMethod.GET,RequestMethod.POST})
	public R offsetRecord(@PathVariable("metaId")Long metaId,@RequestParam("id")Long id,@RequestParam("step")Integer step) {
		try {
			metaService.moveRecord(metaId, id, step);
			return R.ok;
		}catch(Exception e) {
			e.printStackTrace();
			return R.fail;
		}
	}
	
	
	
	
	
	@ApiOperation("删除记录")
	@RequestMapping(value="/deleteBySids",method= {RequestMethod.GET,RequestMethod.POST})
	public R batchDeleteRecord(@RequestParam("metaId")Long metaId,@RequestParam("ids")Collection<Long> ids) {
		try {
			Meta meta=metaService.getMetaById(metaId);
			String sql=new StringBuilder("delete from ")
					.append(meta.getName())
					.append(" where ")
					.append(meta.getPKField().getName())
					.append(" in(")
					.append(StringUtils.join(ids,","))
					.append(")")
					.toString();
			jdbcTemplate.update(sql);
			return R.ok;
		}catch(Exception e) {
			e.printStackTrace();
		}
		return R.fail;
	}
	
	
	
	
	@RequestMapping(value="/getMeta",method= {RequestMethod.GET,RequestMethod.POST})
	public R getMeta(@RequestParam("id")Long id) {
		try {
			return R.ok(metaService.getMetaById(id));
		}catch(Exception e) {
			return R.fail;
		}
		
	}
	
	@RequestMapping(value="/getMetaByName",method= {RequestMethod.GET,RequestMethod.POST})
	public R getMetaByName(@RequestParam("name")String name) {
		try {
			return R.ok(metaService.queryMetaByName(name));
		}catch(Exception e) {
			return R.fail;
		}
		
	}
	@RequestMapping(value="/getEnumListById",method= {RequestMethod.GET,RequestMethod.POST})
	public SimpleList getEnumList(@RequestParam("id")Long id) {
		try {
			Meta meta=metaService.getMetaById(id);
			if(meta==null)return new SimpleList(Collections.emptyList());
			return metaService.getEnumListByName(meta.getCode());
		}catch(Exception e) {
			e.printStackTrace();
			return new SimpleList(Collections.emptyList());
		}
	}
	
	@RequestMapping(value="/getEnumListByName",method= {RequestMethod.GET,RequestMethod.POST})
	public SimpleList getEnumListByName(@RequestParam("name")String name) {
		return metaService.getEnumListByName(name);
	}

	
	@ApiOperation("模型管理界面")
	@GetMapping("/model.html")
	public ModelAndView getModelMgrView() {
		ModelAndView mv=new ModelAndView("gui/tab");
		mv.addObject("title", "模型定义");
		mv.addObject("jsfile", "meta.meta_data");
		return mv;
	}
	
	@ApiOperation("模型字段管理界面")
	@GetMapping("/model/schema.html")
	public ModelAndView getModelSchemaView(@RequestParam("id")Long id) {
		Long metaId=210309L;
		Meta meta=metaService.getMetaById(metaId);
		ModelAndView mv=new ModelAndView("gui/tab");
		mv.addObject("title", "模型字段");
		mv.addObject("id", id);
		mv.addObject("metaData",meta);
		mv.addObject("jsfile", "meta.model_schema");
		return mv;
	}
	
	
	
	@ApiOperation("通用模型菜单界面")
	@GetMapping("/menu/page")
	public ModelAndView commonMenuPage(@PathVariable("id")Long id) {
		ModelAndView mv=new ModelAndView("gui/tab");
		mv.addObject("title", "模型字段");
		mv.addObject("id", id);
		mv.addObject("jsfile", "meta.model_schema");
		return mv;
	}
	
	@ApiOperation("模型属性配置界面")
	@GetMapping("/model/attr.html")
	public ModelAndView getModelAttrView(@RequestParam("id")Long id) {
		ModelAndView mv=new ModelAndView("gui/tab");
		mv.addObject("title", "模型属性");
		mv.addObject("id", id);
		mv.addObject("jsfile", "meta.model_attr");
		return mv;
	}
	
	@ApiOperation("模型属性配置界面")
	@GetMapping("/model/mark.html")
	public ModelAndView getModelMarkView(@RequestParam("id")Long id) {
		ModelAndView mv=new ModelAndView("gui/tab");
		mv.addObject("title", "模型备注");
		mv.addObject("id", id);
		mv.addObject("jsfile", "meta.model_mark");
		return mv;
	}
	
	
	
	@ApiOperation("旧查询模型字段")
	@RequestMapping(value="/model/schema",method= {RequestMethod.GET,RequestMethod.POST})
	public List<MField> queryModelSchema(@RequestParam("id")Long id){
		Meta meta=metaService.getMetaById(id);
		return meta.getFields();
	}

	
	
	@ApiOperation("保存属性")
	@PostMapping("/saveAttrs/{modelId}/{id}")
	public R saveAttr(@PathVariable("modelId")Long modelId,@PathVariable("id")Long id,
			@RequestBody Map<String,String> data) {
		try {
		int rs=dataService.saveAttrs(id, data, modelId);
		return R.ok(rs);
		}catch(Exception e) {
			e.printStackTrace();
			return R.fail(e.getMessage());
		}
	}
	
	
	
	
	@ApiOperation("移动记录")
	@PostMapping("/moveSeq")
	public R moveSeq(@RequestParam("modelId")Long modelId,@RequestParam("id")Long id,
			@RequestParam("step")Integer step) {
		return R.ok;
		
	}
}
